from hashlib import md5
import time


def encodeBase64(data: str) -> str:
    """
    专用Base64编码方式
    :param data:
    :return:
    """
    _0x3f254c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    _0x12dfbf = len(data)
    _0x2d9207 = 0
    _0x50ecd9 = ''
    while _0x2d9207 < _0x12dfbf:
        _0x6300ad = ord(data[_0x2d9207]) & 255
        _0x2d9207 += 1
        if _0x2d9207 == _0x12dfbf:
            _0x50ecd9 += _0x3f254c[_0x6300ad >> 2]
            _0x50ecd9 += _0x3f254c[(_0x6300ad & 3) << 4]
            _0x50ecd9 += '=='
            break
        _0x36c24f = ord(data[_0x2d9207])
        _0x2d9207 += 1
        if _0x2d9207 == _0x12dfbf:
            _0x50ecd9 += _0x3f254c[_0x6300ad >> 2]
            _0x50ecd9 += _0x3f254c[(_0x6300ad & 3) << 4 | (_0x36c24f & 240) >> 4]
            _0x50ecd9 += _0x3f254c[(_0x36c24f & 15) << 2]
            _0x50ecd9 += '='
            break
        _0x8a2fef = ord(data[_0x2d9207])
        _0x2d9207 += 1
        _0x50ecd9 += _0x3f254c[_0x6300ad >> 2]
        _0x50ecd9 += _0x3f254c[(_0x6300ad & 3) << 4 | (_0x36c24f & 240) >> 4]
        _0x50ecd9 += _0x3f254c[(_0x36c24f & 15) << 2 | (_0x8a2fef & 192) >> 6]
        _0x50ecd9 += _0x3f254c[_0x8a2fef & 63]
    return _0x50ecd9


def decodeBase64(data: str) -> str:
    """
    专用Base64解码方式
    :param data: 编码字符串
    :return: 解码结果
    """
    _0x493f0c = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55,
                 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
                 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
                 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1]
    _0x414d10 = len(data)
    _0x33f102 = 0
    _0x3ca267 = ''

    def charCodeAt(index):
        r = 0
        if index < len(data):
            r = ord(data[index]) & 255
        return r

    while _0x33f102 < _0x414d10:
        while True:
            _0x3ce793 = _0x493f0c[charCodeAt(_0x33f102)]
            _0x33f102 += 1
            if _0x33f102 < _0x414d10 and _0x3ce793 == -1:
                pass
            else:
                break
        if _0x3ce793 == -1:
            break
        while True:
            _0x4ba47d = _0x493f0c[charCodeAt(_0x33f102)]
            _0x33f102 += 1
            if _0x33f102 < _0x414d10 and _0x4ba47d == -1:
                pass
            else:
                break
        if _0x4ba47d == -1:
            break

        _0x3ca267 += chr(_0x3ce793 << 2 | (_0x4ba47d & 48) >> 4)
        while True:
            _0x5cbf05 = charCodeAt(_0x33f102)
            _0x33f102 += 1
            if _0x5cbf05 == 61:
                return _0x3ca267
            _0x5cbf05 = _0x493f0c[_0x5cbf05]
            if _0x33f102 < _0x414d10 and _0x5cbf05 == -1:
                pass
            else:
                break
        if _0x5cbf05 == -1:
            break
        _0x3ca267 += chr((_0x4ba47d & 15) << 4 | (_0x5cbf05 & 60) >> 2)
        while True:
            _0x353ba9 = charCodeAt(_0x33f102)
            _0x33f102 += 1
            if _0x353ba9 == 61:
                return _0x3ca267
            _0x353ba9 = _0x493f0c[_0x353ba9]
            if _0x33f102 < _0x414d10 and _0x353ba9 == -1:
                pass
            else:
                break
        if _0x353ba9 == -1:
            break
        _0x3ca267 += chr((_0x5cbf05 & 3) << 6 | _0x353ba9)
    return _0x3ca267


def encodeMd5(context):
    return md5(context.encode("utf8")).hexdigest()


def float_and_time10(_0x36598a=None):
    ot = time.time()
    _0x57e904 = int(ot * 1000)
    _0x2b141a = int(ot)
    if _0x36598a:
        return _0x57e904 / 1000
    else:
        return str((_0x57e904 - _0x2b141a * 1000) / 1000) + ' ' + str(_0x2b141a)


def getTime10():
    return int(time.time())


def authCode(encrypt_data, method="DECODE", password="liangcheng", magic_number=0):
    magic_number01 = 4
    password = encodeMd5(password)
    word_0_16_md5 = encodeMd5(password[0:16])
    word_16_32_md5 = encodeMd5(password[16:32])
    if magic_number01:
        if method == 'DECODE':
            encrypt_data_sub = encrypt_data[0: magic_number01]
        else:
            float_and_time10_md5 = encodeMd5(float_and_time10())
            _0x31be09 = len(float_and_time10_md5) - magic_number01
            encrypt_data_sub = float_and_time10_md5[_0x31be09:_0x31be09 + magic_number01]
    else:
        encrypt_data_sub = ''
    word_encrypt_data = word_0_16_md5 + encodeMd5(
        word_0_16_md5 + encrypt_data_sub)
    encrypt_data_encrypt_str = ""
    if method == 'DECODE':
        encrypt_data = encrypt_data[magic_number01: len(encrypt_data)]
        encrypt_data_encrypt_str = decodeBase64(encrypt_data)
    else:
        if magic_number:
            magic_number = magic_number + getTime10()
        else:
            magic_number = 0
        tmpstr = str(magic_number)
        if len(tmpstr) >= 10:
            encrypt_data = tmpstr[0:10] + md5(encrypt_data + word_16_32_md5)[0:16] + encrypt_data
        else:
            for _ in range(10 - len(tmpstr)):
                tmpstr = '0' + tmpstr
            encrypt_data = tmpstr + encodeMd5(encrypt_data + word_16_32_md5)[0:16] + encrypt_data
        encrypt_data_encrypt_str = encrypt_data

    bufferArray256 = [i for i in range(256)]
    bufferArray = []
    for i in range(256):
        bufferArray.append(ord(word_encrypt_data[i % len(word_encrypt_data)]))
    iii = 0
    for i in range(256):
        iii = (iii + bufferArray256[i] + bufferArray[i]) % 256
        tmp = bufferArray256[i]
        bufferArray256[i] = bufferArray256[iii]
        bufferArray256[iii] = tmp
    result = ''
    encrypt_data_encrypt_str = [i for i in encrypt_data_encrypt_str]
    iii = 0
    ii = 0
    for i in range(len(encrypt_data_encrypt_str)):
        iii = (iii + 1) % 256
        ii = (ii + bufferArray256[iii]) % 256
        tmp = bufferArray256[iii]
        bufferArray256[iii] = bufferArray256[ii]
        bufferArray256[ii] = tmp
        result += chr(
            ord(encrypt_data_encrypt_str[i][0]) ^ bufferArray256[(bufferArray256[iii] + bufferArray256[ii]) % 256])
    if method == 'DECODE':
        if (int(result[0: 10]) == 0 or int(result[0:10]) - getTime10() > 0) and result[10:26] == encodeMd5(
                result[26:len(result)] + word_16_32_md5)[0:16]:
            result = result[26: len(result)]
        else:
            result = ''
    else:
        result = encodeBase64(result)
        result = result.replace('=', '')
        result = encrypt_data_sub + result
    return result


def encode(data, word, magicNumber):
    result = authCode(data, 'ENCODE', word, magicNumber)
    return result.replace("+", "-").replace("/", "_").replace("=", ".")


def decode(data, password):
    data = data.replace("-", "+").replace("_", "/").replace(".", "=")
    return authCode(data, 'DECODE', password=password)


def encodeUrl(data, key):
    """
    加密算法
    :param data: 数据
    :param key: 密匙
    :return: 结果
    """
    return encode(data, key, 0)


def decodeUrl(data, key):
    """
    解密算法
    :param data: 加密数据
    :param key: 密匙
    :return: 解密结果
    """
    return decode(data, key)
